mybatis源码学习 您所在的位置:网站首页 mapper statements mybatis源码学习

mybatis源码学习

#mybatis源码学习| 来源: 网络整理| 查看: 265

DefaultResultSetHandler的handleRowValues方法中有两个分支,一个用于处理嵌套映射,一个用于处理简单映射,本文讲分析其处理嵌套映射的分支。

handleRowValues方法的定义如下:

public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { if (resultMap.hasNestedResultMaps()) {//是否存在嵌套结果映射 //RowBounds配置校验 ensureNoRowBounds(); //ResultHandler校验 checkResultHandler(); handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } else {//简单映射 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } } ensureNoRowBounds

safeRowBoundsEnabled属性的含义为:是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。默认值为false

private void ensureNoRowBounds() { if (configuration.isSafeRowBoundsEnabled() && rowBounds != null && (rowBounds.getLimit() RowBounds.NO_ROW_OFFSET)) { throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. " + "Use safeRowBoundsEnabled=false setting to bypass this check."); } } checkResultHandler

safeResultHandlerEnabled属性的含义为:是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。默认值为true

protected void checkResultHandler() { if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) { throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. " + "Use safeResultHandlerEnabled=false setting to bypass this check " + "or ensure your statement returns ordered data and set resultOrdered=true on it."); } } handleRowValuesForNestedResultMap

处理嵌套映射的代码如下,主要用于解决嵌套 、嵌套和嵌套的情况。

private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { //创建上下文辅助类 final DefaultResultContext resultContext = new DefaultResultContext(); //获取结果集 ResultSet resultSet = rsw.getResultSet(); //跳过指定记录数 skipRows(resultSet, rowBounds); Object rowValue = previousRowValue; //判断能否继续映射结果集中剩余的记录 while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) { //处理鉴别器,确定映射所使用的ResultMap对象 final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null); //为当前记录创建对应的CacheKey对象 final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null); //根据上面创建的从嵌套映射关联的结果对象集合中查询 Object partialObject = nestedResultObjects.get(rowKey); if (mappedStatement.isResultOrdered()) {//resultOrdered属性为真 if (partialObject == null && rowValue != null) {//partialObject为null表示主结果发生变化 //释放nestedResultObjects的空间 nestedResultObjects.clear(); //保存结果对象 storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); } //完成对该记录的映射 rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject); } else { //完成对该记录的映射 rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject); if (partialObject == null) {//partialObject为null表示主结果发生变化 storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); } } } if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) { storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); previousRowValue = null; } else if (rowValue != null) { previousRowValue = rowValue; } }

方法的流程图如下: 在这里插入图片描述

大致了解其流程之后,下面开始详细分析其中的每一步是如何实现的。

skipRows&shouldProcessMoreRow&resolveDiscriminatedResultMap

这三个方法在上一篇分析简单映射中已经做了分析。

createRowKey

该方法用于为当前记录生成一个CacheKey对象,用于标识当前记录对应的结果对象,也可以作为缓存的key。

该方法的逻辑大致如下:

获取ResultMapping数组用于生成CacheKey对象,如果用户配置了或,则会使用配置的id属性集合创建CacheKey对象。如果用户没有配置或,则使用用户显示配置的属性集合创建CacheKey对象如果用户既没有配置或也没有显示配置,则判断ResultMap的type是否为Map类型,如果是Map,则根据所有列名和列值创建CacheKey对象。如果不是Map,使用所有未映射的列名及列值创建CacheKey对象。

代码如下:

private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException { final CacheKey cacheKey = new CacheKey(); cacheKey.update(resultMap.getId()); List resultMappings = getResultMappingsForRowKey(resultMap); if (resultMappings.isEmpty()) { if (Map.class.isAssignableFrom(resultMap.getType())) {//resultMap的类型为Map //根据所有列名和列值创建CacheKey对象 createRowKeyForMap(rsw, cacheKey); } else { //使用所有未映射的列名及列值创建CacheKey对象 createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix); } } else { //使用resultMappings中的列名及列值创建CacheKey对象 createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix); } if (cacheKey.getUpdateCount() List resultMappings = resultMap.getIdResultMappings(); if (resultMappings.isEmpty()) { resultMappings = resultMap.getPropertyResultMappings(); } return resultMappings; } createRowKeyForMap

使用结果集中所有的列名和列值创建CacheKey对象

private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException { List columnNames = rsw.getColumnNames(); for (String columnName : columnNames) { final String value = rsw.getResultSet().getString(columnName); if (value != null) { cacheKey.update(columnName); cacheKey.update(value); } } } createRowKeyForUnmappedProperties

使用所有未映射的列明及列值创建CacheKey对象

private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException { final MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory); List unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix); for (String column : unmappedColumnNames) { String property = column; //如果前缀不为空,就为列名拼接前缀 if (columnPrefix != null && !columnPrefix.isEmpty()) { // When columnPrefix is specified, ignore columns without the prefix. if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) { property = column.substring(columnPrefix.length()); } else { continue; } } //metaType对象中存在property属性 if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) { String value = rsw.getResultSet().getString(column); if (value != null) { cacheKey.update(column); cacheKey.update(value); } } } } createRowKeyForMappedProperties

逻辑与上面两个方法类似

private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List resultMappings, String columnPrefix) throws SQLException { for (ResultMapping resultMapping : resultMappings) { if (resultMapping.isSimple()) { final String column = prependPrefix(resultMapping.getColumn(), columnPrefix); final TypeHandler th = resultMapping.getTypeHandler(); List mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix); // Issue #114 if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) { final Object value = th.getResult(rsw.getResultSet(), column); if (value != null || configuration.isReturnInstanceForEmptyRow()) { cacheKey.update(column); cacheKey.update(value); } } } } } getRowValue

通过上一篇简单映射可知getRowValue方法用于对记录值的映射,在处理嵌套映射的时候会调用getRowValue的另一个重载方法来完成对记录值的映射。

getRowValue方法如下:

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException { final String resultMapId = resultMap.getId(); Object rowValue = partialObject;//主记录对象 if (rowValue != null) {//外层对象存在 final MetaObject metaObject = configuration.newMetaObject(rowValue); putAncestor(rowValue, resultMapId); //处理嵌套映射 applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false); ancestorObjects.remove(resultMapId); } else {//外层对象不存在 final ResultLoaderMap lazyLoader = new ResultLoaderMap(); //创建外层对象 rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix); if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { final MetaObject metaObject = configuration.newMetaObject(rowValue); boolean foundValues = this.useConstructorMappings; if (shouldApplyAutomaticMappings(resultMap, true)) {//是否处理自动映射 foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues; } //处理属性集合 foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues; //维护当前结果对象和所属resultMap的关系 putAncestor(rowValue, resultMapId); //处理嵌套映射 foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues; //移除外层对象 ancestorObjects.remove(resultMapId); foundValues = lazyLoader.size() > 0 || foundValues; rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null; } if (combinedKey != CacheKey.NULL_CACHE_KEY) { nestedResultObjects.put(combinedKey, rowValue); } } return rowValue; } applyNestedResultMappings

通过ancestorObjects集合来处理循环引用问题,如果发现存在循环引用则判断需要的对象是否在ancestorObjects集合中存在。如果存在则复用之前已经创建好的对象,如果不存在才会创建新对象。

private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) { boolean foundValues = false; for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) { final String nestedResultMapId = resultMapping.getNestedResultMapId(); if (nestedResultMapId != null && resultMapping.getResultSet() == null) {//存在嵌套映射的情况 try { final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping); //获取嵌套的ResultMap对象 final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix); if (resultMapping.getColumnPrefix() == null) { //处理循环依赖的逻辑 Object ancestorObject = ancestorObjects.get(nestedResultMapId); if (ancestorObject != null) { if (newObject) { linkObjects(metaObject, resultMapping, ancestorObject); // issue #385 } continue; } } final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix); //合并两个cacheKey final CacheKey combinedKey = combineKeys(rowKey, parentRowKey); Object rowValue = nestedResultObjects.get(combinedKey); boolean knownValue = rowValue != null; //如果当前属性是集合类型的话,先对该属性进行初始化 instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory //判断当前属性是否配置了必须非空,如果为真,则需要创建该属性对应的对象并复制 if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) { //递归处理多层嵌套情况 rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue); if (rowValue != null && !knownValue) { //关联内外层对象 linkObjects(metaObject, resultMapping, rowValue); foundValues = true; } } } catch (SQLException e) { throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'. Cause: " + e, e); } } } return foundValues; } linkObjects

将当前对象设置到所属的外层对象的对应属性中

private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) { final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); if (collectionProperty != null) { final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty); targetMetaObject.add(rowValue); } else { metaObject.setValue(resultMapping.getProperty(), rowValue); } } combineKeys

合并两个CacheKey对象

private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) { if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) { CacheKey combinedKey; try { combinedKey = rowKey.clone(); } catch (CloneNotSupportedException e) { throw new ExecutorException("Error cloning cache key. Cause: " + e, e); } combinedKey.update(parentRowKey); return combinedKey; } return CacheKey.NULL_CACHE_KEY; } instantiateCollectionPropertyIfAppropriate

如果当前属性在助对象中是集合类型,则创建一个ArrayList实例,并赋给主对象,防止后面的操作出现空指针异常

private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) { final String propertyName = resultMapping.getProperty(); Object propertyValue = metaObject.getValue(propertyName); if (propertyValue == null) { Class type = resultMapping.getJavaType(); if (type == null) { type = metaObject.getSetterType(propertyName); } try { if (objectFactory.isCollection(type)) { propertyValue = objectFactory.create(type); metaObject.setValue(propertyName, propertyValue); return propertyValue; } } catch (Exception e) { throw new ExecutorException("Error instantiating collection property for result '" + resultMapping.getProperty() + "'. Cause: " + e, e); } } else if (objectFactory.isCollection(propertyValue.getClass())) { return propertyValue; } return null; } anyNotNullColumnHasValue

notNullColumn属性的作用:默认情况下,在至少一个被映射到属性的列不为空时,子对象才会被创建。 你可以在这个属性上指定非空的列来改变默认行为,指定后,Mybatis 将只在这些列非空时才创建一个子对象。可以使用逗号分隔来指定多个列。默认值:未设置(unset)。

在结果集中任何一个非空的列存在值则直接返回true。

private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSetWrapper rsw) throws SQLException { Set notNullColumns = resultMapping.getNotNullColumns(); if (notNullColumns != null && !notNullColumns.isEmpty()) { ResultSet rs = rsw.getResultSet(); for (String column : notNullColumns) { rs.getObject(prependPrefix(column, columnPrefix)); if (!rs.wasNull()) { return true; } } return false; } else if (columnPrefix != null) { for (String columnName : rsw.getColumnNames()) { if (columnName.toUpperCase().startsWith(columnPrefix.toUpperCase())) { return true; } } return false; } return true; }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有